package com.huiquan.foundation.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.huiquan.analysis.constants.AnalysisSentenceConstant;
import com.huiquan.analysis.utils.ListUtil;
import com.huiquan.foundation.dao.SubpackageDao;
import com.huiquan.foundation.domain.Subpackage;
import com.huiquan.framework.base.BaseService;
import com.huiquan.management.constant.GradeContants;
import com.huiquan.management.dao.GradeDao;
import com.huiquan.management.dao.GradeParamDao;
import com.huiquan.management.domain.Grade;
import com.huiquan.management.domain.GradeParam;

/**
 * @author lichao email:lichao@witspring.com
 * @Description: 分包service
 * @Date 2017/11/21 10:13
 * @since Ver V
 */
@Service
public class SubpackageService extends BaseService {

    @Autowired
    private SubpackageDao subpackageDao;

    @Autowired
    private GradeDao gradeDao;

    @Autowired
    private GradeParamDao gradeParamDao;

    /**
     * 每个数据包中的id的数量
     */
    private static final Integer subpackageSize = 16;

    /**
     * 执行初始化分包
     *
     * @param type
     * @param param
     */
    public void doInitSubpackage(int type, String param) {
        if (GradeContants.TYPE_ANALYSIS_XBS_IMAGEOLOGY == type) {
            doInitSubpackageForAnalysisXbsImageology(param);
        }

    }

    /**
     * 专为现病史中的器械检查数据做初始化分包操作
     *
     * @param param
     */
    private void doInitSubpackageForAnalysisXbsImageology(String param) {
        List<GradeParam> gradeParams = getLevelGradeParam(GradeContants.TYPE_ANALYSIS_XBS_IMAGEOLOGY);
        if (gradeParams == null) {
            LOGGER.error("无等级分词信息，初始化分包数据失败");
            return;
        }
        List<Long> sentenceUnlabelIdList;
        for (int i = 0; i < gradeParams.size(); i++) {
            // 得到未标记的语句id列表
            if (i == gradeParams.size() - 1) {
                int lengthLowerLimit = Integer.parseInt(gradeParams.get(i).getParam());
                sentenceUnlabelIdList = subpackageDao.selectSentenceUnlabelIdList(AnalysisSentenceConstant.TYPE_XBS, AnalysisSentenceConstant.XBS_SOURCE_TYPE_IMAGEOLOGY_INFO, lengthLowerLimit, null);
            } else {
                int lengthLowerLimit = Integer.parseInt(gradeParams.get(i).getParam());
                int lengthUpperLimit = Integer.parseInt(gradeParams.get(i + 1).getParam());
                sentenceUnlabelIdList = subpackageDao.selectSentenceUnlabelIdList(AnalysisSentenceConstant.TYPE_XBS, AnalysisSentenceConstant.XBS_SOURCE_TYPE_IMAGEOLOGY_INFO, lengthLowerLimit, lengthUpperLimit);
            }
            if (sentenceUnlabelIdList == null || sentenceUnlabelIdList.size() == 0) {
                continue;
            }
            // 裁掉20%的数据下来供谭姐标注，保留80%的数据用作分包。
            sentenceUnlabelIdList = cutIdList(sentenceUnlabelIdList, 0.8d);
            initSubpackageData(GradeContants.TYPE_ANALYSIS_XBS_IMAGEOLOGY, i + 1, sentenceUnlabelIdList, subpackageSize, param);
        }
        LOGGER.info("初始化器械检查分包数据成功");
    }

    /**
     * 截取idList
     *
     * @param idList     id列表
     * @param percentage 保留的百分比(0-1的浮点数)
     * @return
     */
    private List<Long> cutIdList(List<Long> idList, double percentage) {
        if (ListUtil.isEmpty(idList)) {
            LOGGER.info("截取idList错误，idList为空");
            return idList;
        }
        if (percentage > 1 || percentage < 0) {
            LOGGER.info("截取idList错误，百分比输入错误");
            return idList;
        }
        // 计算按比例截取后的list大小
        int size = BigDecimal.valueOf(idList.size()).multiply(BigDecimal.valueOf(percentage)).intValue();
        return idList.subList(0, size);
    }

    /**
     * 得到分词信息列表
     *
     * @param type
     * @return
     */
    public List<GradeParam> getLevelGradeParam(int type) {
        Map<String, Object> param = new HashMap<>();
        param.put("type", type);
        Grade grade = gradeDao.retrieveObjectByMap(param);
        if (grade == null) {
            LOGGER.error("没有等级数据");
            return null;
        }
        param.put("gradeId", grade.getId());
        param.put("type", GradeContants.PARAM_TYPE_VOCABULARY_NUM_IN_SENTENCE);
        return gradeParamDao.retrieveList(param);
    }


    /**
     * 初始化分包数据
     *
     * @param type  分包数据类型
     * @param level 分包数据等级
     * @param list  分包数据列表
     * @param size  分包数据size
     * @param param 其他参数
     */
    private void initSubpackageData(int type, Integer level, List<Long> list, int size, String param) {
        if (ListUtil.isEmpty(list)) {
            LOGGER.error("数据list为空，初始化失败");
            return;
        }
        int count = 0;
        StringBuilder idPackage = new StringBuilder();
        List<String> idpackageList = new ArrayList<>();
        idPackage.reverse();
        while (count + size <= list.size()) {
            for (Long id : list.subList(count, count + size)) {
                idPackage.append(id).append(",");
            }
            idpackageList.add(idPackage.substring(0, idPackage.length() - 1));
            // 清空StringBuffer
            idPackage.setLength(0);
            count = count + size;
        }
        if (list.size() - count > 0) {
            for (Long id : list.subList(count, list.size())) {
                idPackage.append(id).append(",");
            }
            idpackageList.add(idPackage.substring(0, idPackage.length() - 1));
        }
        subpackageDao.deleteDataWithType(type, level);
        subpackageDao.batchInsertForInit(type, level, idpackageList, param);
    }

    /**
     * 分配包数据给用户
     *
     * @param type
     * @param level
     * @param param
     * @param uid
     * @return
     */
    public String subpackageToUser(int type, String level, String param, long uid) {
        // 检索未分配包数据
        Subpackage subpackage = subpackageDao.selectUndistributedData(type, level, param);
        if (subpackage == null) {
            LOGGER.error("无可分配包数据，分包失败");
            return null;
        }
        // 更新用户id到包数据
        subpackageDao.updateUidWithId(subpackage.getId(), uid);
        // 把包数据在bas_analysis_sentence中置为半标注
        subpackageDao.updateSentenceStatusToHalfLabeled(subpackage.getIdPackage());
        return subpackage.getIdPackage();
    }

    private static final int levelSize = 1000;

    /**
     * 得到给用户的sidList
     *
     * @param secondType
     * @param uid
     * @return
     */
    @Deprecated
    public List<Long> getSidListToUser(String secondType, long uid) {
        // 获取词库中所有词的个数
        int dataTotal = subpackageDao.getDataCount(secondType);
        // 等级数目
        int levelTotal = dataTotal / levelSize;
        if (dataTotal % levelSize > 0) {
            levelTotal++;
        }
        List<Long> sidList = new ArrayList<>();
        for (int i = 0; i < levelTotal; i++) {
            // 获取用户相关等级的数据的count，如果为0则跳过
            if (subpackageDao.getLevelDataCountWithUid(secondType, uid, i, levelSize) == 0) {
                continue;
            }
            // 获取用户相关等级的数据
            List<Long> list = subpackageDao.getLevelDataWithUid(secondType, uid, i, levelSize);
            if (ListUtil.isEmpty(list)) {
                continue;
            }
            sidList.addAll(list);
            if (sidList.size() >= 16) {
                sidList = sidList.subList(0, 16);
                break;
            }
        }
        if (ListUtil.isEmpty(sidList)) {
            LOGGER.error("无法获取用户所需sidList数据");
            return null;
        }
        // 把sidList里的数据写入到bas_sentence_user中
        subpackageDao.insertSentenceUserRelation(uid, sidList);
        // 把sidList里的数据在bas_analysis_sentence中置为半标注
        StringBuilder sb = new StringBuilder();
        for (Long sid : sidList) {
            sb.append(sid).append(",");
        }
        subpackageDao.updateSentenceStatusToHalfLabeled(sb.substring(0, sb.length() - 1));
        return sidList;
    }


    /**
     * 校验用户提交的数据
     *
     * @param sid
     */
    @Deprecated
    public void checkUserCommit(long sid) {
        // sid对应的已标记的语句的个数
        int labeledCount = subpackageDao.selectLabeledSentenceCountWithSid(sid);
        // 如果个数不足3，不校验标记结果
        if (labeledCount < 3) {
            LOGGER.info("sid[{}]对应已标记语句个数不足3个，不校验", sid);
            return;
        }

        // 校验标记结果是否一致
        LOGGER.info("开始校验");
        List<String> checkStrList = subpackageDao.selectCheckStrListFromOutsourcingSentenceWithSid(sid);
        if (checkListElementEquals(checkStrList)) {
            // 把sid对应的bas_analysis_sentence语句的标记状态(labelStatus)置为已标记(1)
            subpackageDao.updateAnalysiSentenceToLabeled(sid);
            LOGGER.info("校验结果为一致，sid[{}]对应数据置为已标记", sid);
        } else {
            subpackageDao.insertOutsourcingSentenceStatus(sid);
            LOGGER.info("校验结果为不一致，sid[{}]对应数据置为待校验", sid);
        }
    }

    /**
     * 把标记次数小于三的数据的rank值提高为1
     */
    public void updateRankForUnfinishedLabeled() {
        subpackageDao.updateRankForUnfinishedLabeled();
    }

    /**
     * 判断list中所有元素是否相等
     *
     * @param checkStrList
     * @return 全部相等返回true，否则返回false
     */
    private boolean checkListElementEquals(List<String> checkStrList) {
        Set<String> set = new HashSet<>(checkStrList);
        return set.size() == 1;
    }
}
